package model;

import java.awt.Image;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.io.Serializable;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

/**
 * Model Klasse für die Einstellungen
 * jeder Einstellungsparameter bekommt ein eigenes model von Typ <code>javax.swing.SpinnerNumberModel</code> für die Datenhaltung
 */
public class Model_Config implements Serializable {

    private MySpinnerModel linesPerImageModel, imagesPerGenerationModel;
    // Welcher Algorithmus fuer das Skalieren des fittestImage genutzt werden soll.
    private MyComboBoxModel scaleHintModel;

    public int getImagesPerGeneration() {
        return this.imagesPerGenerationModel != null ? this.imagesPerGenerationModel.getMyValue() : -1;
    }

    public void setImagesPerGeneration(int imagesPerGeneration) {
        this.imagesPerGenerationModel.setMyValue(imagesPerGeneration);
    }

    public int getLinesPerImage() {
        return this.linesPerImageModel != null ? linesPerImageModel.getMyValue() : -1;
    }

    public void setLinesPerImage(int linesPerImage) {
        this.linesPerImageModel.setMyValue(linesPerImage);
    }

    public int getScaleHint() {
        return this.scaleHintModel != null ? this.scaleHintModel.getScaleHint() : -1;
    }

    /**
     * erzeugt ein neues SpinnerModel fuer die Anzahl der Striche pro Bild und gibt dieses zurueck
     * @param value aktueller Wert des SpinnerModels
     * @param minValue Minimalwert
     * @param maxValue Maximalwert
     * @param stepSize Groesse eines Schrittes
     * @return das erzeugte SpinnerModel
     */
    public MySpinnerModel createMySpinnerModel_linesPerImage(int value, int minValue, int maxValue, int stepSize) {
        this.linesPerImageModel = new MySpinnerModel(value, minValue, maxValue, stepSize);
        return this.linesPerImageModel;
    }

    /**
     * erzeugt ein neues SpinnerModel fuer die Anzahl der Bilder pro Generation und gibt dieses zurueck
     * @param value aktueller Wert des SpinnerModels
     * @param minValue Minimalwert
     * @param maxValue Maximalwert
     * @param stepSize Groesse eines Schrittes
     * @return das erzeugte SpinnerModel
     */
    public MySpinnerModel createMySpinnerModel_imagesPerGeneration(int value, int minValue, int maxValue, int stepSize) {
        this.imagesPerGenerationModel = new MySpinnerModel(value, minValue, maxValue, stepSize);
        return this.imagesPerGenerationModel;
    }

    /**
     * erzeugt ein ComboboxModel fuer die Skalierungart
     * @return das erzeugt ComboBoxModel
     */
    public MyComboBoxModel createMyComboboxModel_scale() {
        this.scaleHintModel = new MyComboBoxModel();
        return this.scaleHintModel;
    }

    /**
     * erzeugt einen MouseWheelListener, angepasst fuer unsere Spinner
     * @param wheelListenerIsFor
     * @return new MouseWheelListener
     */
    public MySpinnerModelMouseWheelListener createWheelListener(JSpinner wheelListenerIsFor) {
        return new MySpinnerModelMouseWheelListener(wheelListenerIsFor);
    }

    /**
     * eine Kapselung des MouseWheelListeners
     * als minValue wird 1 vorausgesetzt
     */
    protected class MySpinnerModelMouseWheelListener implements MouseWheelListener {

        JSpinner spinner;
        final int MIN = 1;

        public MySpinnerModelMouseWheelListener(JSpinner spinner) {
            this.spinner = spinner;
        }

        public void mouseWheelMoved(MouseWheelEvent e) {
            int val = Integer.parseInt("" + spinner.getValue());
            spinner.setValue(val - e.getWheelRotation());
            if (Integer.parseInt("" + spinner.getValue()) <= MIN) {
                spinner.setValue(MIN);
            }
        }
    }

    /**
     * das SpinnerNumberModel fuer unsere Zwecke angepasst
     */
    protected class MySpinnerModel extends SpinnerNumberModel {

        private int myValue = 0;

        public MySpinnerModel(int value, int minValue, int maxValue, int stepSize) {
            super(value, minValue, maxValue, stepSize);
            this.myValue = value;
        }

        @Override
        protected void fireStateChanged() {
            this.myValue = Integer.parseInt("" + this.getValue());
            super.fireStateChanged();
        }

        protected int getMyValue() {
            return this.myValue;
        }

        protected void setMyValue(int value) {
            this.myValue = value;
        }
    }

    /**
     * das DefaultComboBoxModel für unsere Zwecke angepasst
     */
    protected class MyComboBoxModel extends DefaultComboBoxModel {

        {
            addElement(ScaleHint.schnell);
            addElement(ScaleHint.standard);
            addElement(ScaleHint.weich);
        }

        /**
         * gibt den Image.SCALE_* hint wieder sodass einstellbar ist welche Alg beim Scallieren benutzt werden soll
         */
        public int getScaleHint() {
            ScaleHint sel = (ScaleHint) getSelectedItem();
            switch (sel) {
                case standard:
                    return Image.SCALE_DEFAULT;
                case schnell:
                    return Image.SCALE_FAST;
                case weich:
                    return Image.SCALE_SMOOTH;
                default:
                    return -1;
            }
        }
    }

    /**
     *  Wahlmoeglichkeiten des ComboboxModel
     */
    enum ScaleHint implements Serializable {

        schnell, standard, weich
    }
}
